﻿using System;
using System.Collections.Generic;
using System.Data;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading.Tasks;
using Dapper;
using GameCell.ConfigDataMaker.Configs;
using MySql.Data.MySqlClient;
using NPOI.HSSF.UserModel;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;

namespace GameCell.ConfigDataMaker
{
    public class ConfigData
    {
        private string FilePath;
        private int Sheet;
        private string Id;
        public ConfigData(string filePath, int sheet, string id)
        {
            FilePath = filePath;
            Sheet = sheet;
            Id = id;
        }

        public static IEnumerable<T> ReadFromFile<T>()
        {
            string filename = "configs/" + typeof(T).Name + ".dat";
            Stream fStream = new FileStream(filename, FileMode.Open, FileAccess.Read);
            BinaryFormatter binFormat = new BinaryFormatter();//创建二进制序列化器
            var source = (IEnumerable<T>)binFormat.Deserialize(fStream);//反序列化对象
            fStream.Close();
            return source;
        }

        public static IEnumerable<T> ReadFromDb<T>(string connStr)
            where T:new()
        {
            List<T> dest = new List<T>();
            using (MySqlConnection conn = new MySqlConnection(connStr))
            using (MySqlCommand command = new MySqlCommand(string.Format("select * from `{0}`;", typeof (T).Name), conn))
            using(MySqlDataAdapter adapter = new MySqlDataAdapter(command))
            {
                DataTable table = new DataTable();
                adapter.Fill(table);
                foreach (DataRow dataRow in table.Rows)
                {
                    T t = new T();
                    dest.Add(t);
                    foreach (PropertyInfo p in typeof (T).GetProperties())
                    {
                        string value = dataRow[p.Name].ToString();
                        if (p.PropertyType==typeof(double))
                        {
                            p.SetValue(t, double.Parse(value));
                        }
                        else if (p.PropertyType == typeof (float))
                        {
                            p.SetValue(t, float.Parse(value));
                        }
                        else if (p.PropertyType == typeof(int))
                        {
                            p.SetValue(t, int.Parse(value));
                        }
                        else if (p.PropertyType == typeof(string))
                        {
                            p.SetValue(t, value);
                        }
                        else if (p.PropertyType == typeof(int[]))
                        {
                            p.SetValue(t, value.Split(new []{","}, StringSplitOptions.RemoveEmptyEntries).Select(int.Parse).ToArray());
                        }
                        else if (p.PropertyType == typeof(bool))
                        {
                            p.SetValue(t, bool.Parse(value));
                        }
                    }
                }
            }
            return dest;
        } 

        public IEnumerable<T> Parse<T>()
            where T:new()
        {
            IWorkbook workbook = new XSSFWorkbook(FilePath);
            ISheet sheet = workbook.GetSheetAt(Sheet);
            List<ConfigInfo> configInfos = new List<ConfigInfo>();
            List<T> configs = new List<T>();
            Type classType = typeof (T);
            for (int i = sheet.FirstRowNum + 1; i <= sheet.LastRowNum; i++)
            {
                var row = sheet.GetRow(i);
                if (i == 1)
                {
                    foreach (ICell cell in row.Cells)
                    {
                        string[] tmp = cell.StringCellValue.Split(new[] {":"}, StringSplitOptions.RemoveEmptyEntries);
                        configInfos.Add(new ConfigInfo()
                        {
                            Name = tmp[0].Trim(' '),
                            Type = tmp[1].Trim(' ')
                        });
                    }
                }
                else
                {
                    if (row.Cells.Count != configInfos.Count)
                    {
                        continue;
                    }
                    T config = new T();
                    configs.Add(config);
                    for (int j = 0; j< row.Cells.Count ;j++)
                    {
                        ICell cell = row.Cells[j];
                        switch (cell.CellType)
                        {
                            case CellType.Numeric:
                                switch (configInfos[j].Type)
                                {
                                    case "double":
                                        typeof(T).GetProperty(configInfos[j].Name).SetValue(config, (double)cell.NumericCellValue);
                                        break;
                                    case "int":
                                        string propName = configInfos[j].Name;
                                        var prop = classType.GetProperty(propName);
                                        prop.SetValue(config, (int)cell.NumericCellValue);
                                        break;
                                    case "float":
                                        typeof(T).GetProperty(configInfos[j].Name).SetValue(config, (float)cell.NumericCellValue);
                                        break;
                                }
                                break;
                            case CellType.String:
                                switch (configInfos[j].Type)
                                {
                                    case "int":
                                        string stringVlaue = cell.StringCellValue;
                                        if (stringVlaue.StartsWith("["))
                                        {
                                            typeof(T).GetProperty(configInfos[j].Name).SetValue(config, stringVlaue.Trim(new[] { '[', ']' }).Split(',').Select(int.Parse).ToArray());
                                        }
                                        else
                                        {
                                            typeof(T).GetProperty(configInfos[j].Name).SetValue(config, int.Parse(stringVlaue));
                                        }
                                        break;
                                    case "string":
                                        typeof(T).GetProperty(configInfos[j].Name).SetValue(config, cell.StringCellValue);
                                        break;
                                    case "float":
                                        typeof(T).GetProperty(configInfos[j].Name).SetValue(config, float.Parse(cell.StringCellValue));
                                        break;
                                    case "double":
                                        typeof(T).GetProperty(configInfos[j].Name).SetValue(config, double.Parse(cell.StringCellValue));
                                        break;
                                }
                                break;
                            case CellType.Boolean:
                                typeof(T).GetProperty(configInfos[j].Name).SetValue(config, cell.BooleanCellValue);
                                break;
                        }
                    }
                }
            }
            return configs;
        }
    }

    public enum ConfigType
    {
        IntArray,
        String,
        Int,
        Bool,
    }

    public class ConfigInfo
    {
        public string Name { get; set; }
        public string Type { get; set; }
    }
}
